package com.lry.jvm.classfile.attributes;

import com.lry.jvm.classfile.ClassReader;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Data
public class RuntimeVisibleAnnotations implements AttributeInfo {

    private int numOfAnnotations;

    private Annotation[] annotations;

    @Override
    public void readInfo(ClassReader reader) {
        numOfAnnotations = reader.nextU2ToInt();
        annotations = new Annotation[numOfAnnotations];

        for(int i=0;i<numOfAnnotations;i++){
            annotations[i] = readAnnotation(reader);
        }
    }

    private List<Character> tags =  Arrays.asList('B','C','D','F','I','J','S','Z','s');

    private boolean isContains(int tag){
        for (Character character : tags) {
            if(tag==character.charValue())
                return true;
        }
        return false;
    }

    private Annotation readAnnotation(ClassReader reader){
        Annotation annotation = new Annotation();
        annotation.setTypeIndex(reader.nextU2ToInt());
        annotation.setNumOfElements(reader.nextU2ToInt());

        AnnotationElement[] elements = new AnnotationElement[annotation.getNumOfElements()];

        for(int i=0;i<elements.length;i++){
            AnnotationElement element = new AnnotationElement();
            element.setElementNameIndex(reader.nextU2ToInt());

            ElementValue elementValue = readElementValue(reader);
            element.setElementValue(elementValue);
            elements[i] = element;
        }

        annotation.setElements(elements);
        return annotation;
    }

    private ElementValue readElementValue(ClassReader reader){
        ElementValue elementValue = new ElementValue();
        int tag = reader.nextU1ToInt();
        elementValue.setTag(tag);

        if(isContains(tag)){
            int constValueIndex = reader.nextU2ToInt();
            elementValue.setConstValueIndex(constValueIndex);
        }
        //枚举
        else if(tag=='e'){
            int typeNameIndex = reader.nextU2ToInt();
            int constNameIndex = reader.nextU2ToInt();
        }
        //Class
        else if(tag=='c'){
            int classInfoIndex = reader.nextU2ToInt();
        }
        //注解
        else if(tag=='@'){
            readAnnotation(reader);
        }
        //数组
        else if(tag=='['){
            int numValues = reader.nextU2ToInt();
            ElementValue[] elementValues = new ElementValue[numValues];
            for(int i=0;i<numValues;i++){
                elementValues[i] = readElementValue(reader);
            }
        }
        return elementValue;
    }

    @Getter
    @Setter
    @Data
    class Annotation {
        private int typeIndex;

        private int numOfElements;

        private AnnotationElement[] elements;
    }

    @Getter
    @Setter
    @Data
    class AnnotationElement {

        private int elementNameIndex;

        private ElementValue elementValue;
    }

    @Getter
    @Setter
    @Data
    class ElementValue {

        private int tag;

        private int constValueIndex;

        //private Object value;

    }
}
